﻿#include "VBackgroundSystem.h"
#include "VFunctions.h"
#include "VTranslate.h"
#include "VOutputInformation.h"
#include "VGlobal.h"
#include "VErrorWidget.h"
#include "VFile.h"
#include "VProjectTreeWidget.h"
#include "VNavigationWidget.h"

#include <QFile>
#include <QTextStream>
#include <QRegExp>
#include <QDir>
#include <qstringlist.h>
#include <qdebug.h>
#include <qthread.h>
#include <qprocess.h>
#include <qdatetime.h>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>


VBackgroundSystem::VBackgroundSystem(QObject *parent) : QObject(parent),
_update_timer(this)
{
    init_template();
    init_keyword();
    init_include_dir();
    init_sdcc_source();
    VOutputInformation::init();
	init_update_timer();
}

VBackgroundSystem::~VBackgroundSystem()
{
    foreach(VFileData* obj, _file_data_list)
    {
        delete obj;
    }

//    foreach(VWords* obj, _keyword_list)
//    {
//        delete obj;
//    }

}

void VBackgroundSystem::slot_input_tip(QString path, QString line_text, int line_number, bool in_function)
{

    line_text = text_preprocessing(line_text);


    qDebug() << "path" << path << "input: " << line_text << "number:" << line_number << "  infunction: " << in_function;
    if (line_text.length() == 0)
	{
		emit signals_calltip(QList<VWords*>());
        return;
	}


    QList<VWords*> gobal_scope = init_scope(path, line_number, in_function);
    int change_symbol;
    QList<VWords*> local_scope = match_expression(gobal_scope, line_text, VWords::MODE::PART, &change_symbol);

    if(change_symbol == 1)
    {
        emit signal_change_symbol("->");
    }
    else if(change_symbol == -1)
    {
        emit signal_change_symbol(".");
    }

    // 去掉重复的 function prototype
    for(int i=0; i<local_scope.count(); i++)
    {
        if(local_scope.at(i)->_kind == VWords::FUNCTION
                || local_scope.at(i)->_kind == VWords::PROTOTYPE)
        {
            for(int j=i+1; j<local_scope.count(); j++)
            {
                if((local_scope.at(j)->_kind == VWords::FUNCTION
                        || local_scope.at(j)->_kind == VWords::PROTOTYPE)
                        && local_scope.at(j)->_name == local_scope.at(i)->_name)
                {
                    local_scope.removeAt(j);
                    j--;
                }
            }
        }
    }

    // 拷贝数据 发送到前台
    QList<VWords*> result;
    foreach(VWords *obj, local_scope)
    {
        result.append(new VWords(obj));
    }
    emit signals_calltip(result);

}

void VBackgroundSystem::slot_file_calltip(QString path, QString input)
{
    if (input.length() == 0)
    {
        emit signals_calltip(QList<VWords*>());
        return;
    }

    auto data = get_file_data(path);
    if(data == nullptr)
    {
        emit signals_calltip(QList<VWords*>());
        return;
    }

    QFileInfo info(input);
    QString info_name = info.fileName();
    QString info_path = info.path();

    QList<QFileInfo> temp_list;
    temp_list = search_file(data->_project,QFileInfo(path).path(),
                            VFileData::VHeadFile(info_name, info_path, VFileData::VHeadFileType::STDEX), 'p', true);

    // 排序
    qSort(temp_list.begin(), temp_list.end(), [](const QFileInfo &mfi1, const QFileInfo &mfi2){
        if(mfi1.isFile() && !mfi2.isFile())
        {
            return false;
        }
        return true;
    });

    QList<VWords*> result;
    foreach(const QFileInfo &mfi, temp_list)
    {
        if(mfi.isFile())
        {
            result.append(new VWords(mfi.fileName(), "", "", 0, VWords::KIND::FILE));
        }
        else
        {
            result.append(new VWords(mfi.fileName(), "", "", 0, VWords::KIND::FOLDER));
        }
//        list.append(QFileInfo(path).fileName());
    }

//    list += VFolderData(_now_dir).matching(input);

//    // 去除非.h 文件
//    foreach(QString name, list)
//    {
//        if(QFileInfo(name).suffix() != "h")
//        {
//            list.removeOne(name);
//        }
//    }

//    // 去除重复
//    for(int i=0; i<list.count(); i++)
//    {
//        for(int k=i+1; k<list.count(); k++)
//        {
//            if(list.at(i) == list.at(k))
//            {
//                list.removeAt(k);
//                k--;
//            }
//        }
//    }
    emit signals_calltip(result);
}

void VBackgroundSystem::slot_parameter_calltip(QString path, QString function_name, int parameter_pos, int show_pos)
{
    QString result;

    QList<VWords*> global_scope = init_scope(path);
    QList<VWords*> list = search_scope_word(global_scope, function_name, VWords::KIND::FUNCTION | VWords::KIND::PROTOTYPE,
                                            VWords::MATCH::NAME, -1, VWords::MODE::ALL);

    if(list.count() != 0)
    {
        VWords *p_word = list.at(0);
        QStringList list = p_word->_signature.split(",");
        for (int i = 0; i < list.count(); i++)
        {
            if (i == parameter_pos)
            {
                result += QString("<strong>%1</strong>").arg(list.at(i)) + ", ";
            }
            else
            {
                result += list.at(i) + ", ";
            }
        }

        result.chop(2);

        emit signals_parameter_calltip(result, show_pos);
    }
}

void VBackgroundSystem::slot_mouse_hover_calltip(QString path ,QString pre, QString next, int line_number, bool in_function, int pos)
{

//    qDebug() << next;
    next = text_preprocessing(VFunctions::string_reverse(next));
    next = VFunctions::string_reverse(next);

    int i_pos = next.indexOf(QRegExp("(\\.|->)"));
    if(i_pos != -1)
    {
        next = next.mid(0, i_pos);
    }

    pre = text_preprocessing(pre);

    qDebug() << "slot_mouse_hover_calltip:" << pre+"   " +next;
    qDebug() << QString("path:%1 line:%2 in:%3").arg(path).arg(line_number).arg(in_function);
    QString expression = pre+next;
    if(expression.isEmpty())
    {
        return;
    }

    QList<VWords*> global_scope = init_scope(path, line_number, in_function);

    QString result;
    QList<VWords*> list =  match_expression(global_scope, expression, VWords::MODE::ALL);
    foreach(VWords* obj, list)
    {
        if(obj->_kind == VWords::KIND::KEYWORD)
        {
            continue;
        }

        if(obj->_kind == VWords::KIND::FUNCTION ||
               obj->_kind == VWords::KIND::PROTOTYPE )
        {
            result = QString("<strong>%1</strong> %2(%3)").arg(obj->_type_name)
                    .arg(obj->_name).arg(obj->_signature);
        }
        else
        {
            result = QString("<strong>%1</strong> %2")
                    .arg(obj->_type_name)
                    .arg(obj->_name);
        }

        qDebug() << "emit";
        emit signal_mouse_hover_calltip(result, pos);
    }





//	QList<VWords*> list;
//	// 遍历所有的文件
//    foreach (VFileData* p_file, _now_include_file_list)
//	{
//		if (p_file->_path == _now_path)
//		{
//			list += p_file->matching_string(text, line_number, 0);
//		}
//		else
//		{
//			list += p_file->matching_string(text, -1, 0);
//		}
//	}

//	QString result;
//	if (list.count() > 0)
//	{
////		int type = list.at(0)->_type;
////		if (type == VFunctions::WordType::DEFINE)
////		{
////			result = "<font color=\"#3E98D8\">" + list.at(0)->_modification + "</font> " + list.at(0)->_name;
////		}
////		else if (type == VFunctions::WordType::FUNCTION || type == VFunctions::WordType::FUNCTION_DECLARATION)
////		{
////			result = "<font color=\"#3E98D8\">" + list.at(0)->_modification + "</font> " + list.at(0)->_name + "(";
////			for (int i = 0; i < list.at(0)->_parameter_list.count(); i++)
////			{
////					result += "<font color=\"#3E98D8\">" + list.at(0)->_parameter_list.at(i)->_modification + "</font> " +
////						list.at(0)->_parameter_list.at(i)->_name + ", ";
////			}

////			if (result.at(result.length() - 1) == ' ')
////			{
////				result.chop(2);
////			}

////			result += ")";
////		}
////		else if (type == VFunctions::WordType::GLOBAL)
////		{
////			result = "<font color=\"#3E98D8\">" + list.at(0)->_modification + "</font> " + list.at(0)->_name;
////		}
////		else if (type == VFunctions::WordType::LOCAL)
////		{
////			result = "<font color=\"#3E98D8\">" + list.at(0)->_modification + "</font> " + list.at(0)->_name;
////		}
////		else if (type == VFunctions::WordType::PARAMETER)
////		{
////			result = "<font color=\"#3E98D8\">" + list.at(0)->_modification + "</font> " + list.at(0)->_name;
////		}

//        result = "<strong>" + list.at(0)->_type_name + "</strong> " + list.at(0)->_name;

//		if (result.length() > 0)
//		{
//			emit signal_mouse_hover_calltip(result, pos);
//		}
		
//	}
}

void VBackgroundSystem::slot_jump_request(QString path, QString pre, QString next, int line_number, bool in_function)
{
    QString temp = pre + next;
    if(temp.isEmpty())
    {
        return;
    }
//    qDebug() << temp;

    auto n_file_data = get_file_data(path);
    if(n_file_data == nullptr)
    {
        return;
    }

    if(temp.at(0) == '#'
            && temp.indexOf(QRegExp("#(include|引入)")) != -1)
    {
        QRegularExpression reg;
        QRegularExpressionMatch match;

        reg.setPattern("#(include|引入)\\s+(\"|<)(.+?)(\"|>)");
        match = reg.match(temp);
        if(match.hasMatch())
        {
            QString str = match.captured(3);
            VFileData::VHeadFile head_file;
            head_file.name = QFileInfo(str).fileName();
            head_file.path = QFileInfo(str).path();
            if(match.captured(2) == "\"")
                head_file.type = VFileData::VHeadFileType::STDEX;
            else
                head_file.type = VFileData::VHeadFileType::STD;


            QList<QFileInfo> list = search_file(n_file_data->_project, QFileInfo(path).path(), head_file, 'a');
            if(list.count() > 0)
            {
                emit signal_jump(list.at(0).absoluteFilePath(), 1);
            }
//            foreach(VFileData* data, n_file_data->_include_file_data_list)
//            {
//                if(QFileInfo(data->_path).fileName() == name)
//                {
//                    qDebug() << "VBackgroundSystem::slot_jump_request" << data->_path;
//                    emit signal_jump(data->_path, 1);
//                }
//            }
        }

        return;
    }

    //    qDebug() << next;
    next = text_preprocessing(VFunctions::string_reverse(next));
    next = VFunctions::string_reverse(next);

    int i_pos = next.indexOf(QRegExp("(\\.|->)"));
    if(i_pos != -1)
    {
        next = next.mid(0, i_pos);
    }

    pre = text_preprocessing(pre);

    qDebug() << "slot_mouse_hover_calltip:" << pre+next;
    QString expression = pre+next;
    if(expression.isEmpty())
    {
        return;
    }

    QList<VWords*> global_scope = init_scope(path, line_number, in_function);
    QList<VWords*> list =  match_expression(global_scope, expression, VWords::MODE::ALL);
    foreach(VWords* obj, list)
    {
        if(obj->_kind == VWords::KIND::KEYWORD)
        {
            continue;
        }

        if (obj->_line == line_number)
        {
           continue;
        }

        emit signal_jump(((VFileData*)obj->_file)->_path, obj->_line);
        return;
    }

}

void VBackgroundSystem::slot_update_file_data(QString path, QString text)
{
	qDebug() << "update";
    auto data = load_file_data(path);
    if(data == nullptr) return;
    update_file_text(data, text);
}

void VBackgroundSystem::slot_build(QString esln_path)
{
    auto delete_files = [](QStringList &list){
        foreach(QString path, list)
        {
            QFile(path).remove();
        }
    };

    auto project = get_project_data(esln_path);
    if(project == nullptr) return;

    QStringList c_files;
    QStringList translate_files;
    foreach(QString path, project->_project_file_path_list)
    {
        QFileInfo info(path);
        QString suffix = info.suffix();
        QString base_name = info.completeBaseName();
        if(suffix != "h" && suffix != "c") continue;
        emit_text_to_reception("载入文件" + path);
        auto file = load_file_data(path);
        if(file == nullptr) {
            emit_text_to_reception("文件载入失败" + path);
            return;
        }
        QString save_path = info.path() + "/" + VTranslate::encode_string63(base_name) + "." + suffix;
        translate_file(file->_text, save_path);
        translate_files.append(save_path);

		if (suffix == "c") {
			foreach(VFileData * data, file->_include_file_data_list)
			{
				QFileInfo info(data->_path);
				QString base_name = info.completeBaseName();
				QString suffix = info.suffix();
				QString save_path = info.path() + "/" + VTranslate::encode_string63(base_name) + "." + suffix;
				translate_file(data->_text, save_path);
				translate_files.append(save_path);
			}
			c_files.append(save_path);
		}   
    }



    // 清空rel
    VFile::clear_folder_file(project->_output_list_path, "(rel)(lst)(adb)(rst)");
    // 编译.c
    QStringList linker_list;
    emit signal_append_output_text("执行编译...");
    QProcess p;
    p.setWorkingDirectory(QFileInfo(esln_path).path());
    foreach(QString path, c_files)
    {
        if(QFileInfo(path).suffix() == "c")
        {

            emit_text_to_reception("编译文件:" + path);
            QString rel_path = project->_output_list_path + "/" + QFileInfo(path).baseName() + ".rel";
            QStringList param = project->_cparam_summary;
            param << "-c" << QFileInfo(path).fileName() << "-o" << rel_path;
            emit_text_to_reception(param.join(' '));
            p.start("\"" + VGlobal::sdcc_path + "\"", param);
            if (p.waitForStarted() == false)
            {
                emit_text_to_reception("sdcc 启动失败");
                return;
            }
            p.waitForFinished();
            QString error = QString::fromLocal8Bit(p.readAllStandardError());
            emit_text_to_reception(error);
            emit_translate_build_error_info(QFileInfo(esln_path).path(), error);
            if(QFile(rel_path).exists() == false)
            {
                emit_text_to_reception("生成:" + rel_path + " 失败...");
				if (VGlobal::setting.delete_temp_files)
					delete_files(translate_files);
                return;
            }
            else
            {
                linker_list.append(rel_path);
                emit_text_to_reception("生成:" + rel_path );
            }


        }
    }
    emit_text_to_reception("编译结束...");

    // 清空 cdb ihx map mem omf lk
    VFile::clear_folder_file(project->_output_list_path, "(cdb)(ihx)(mem)(omf)(lk)");
    // 链接
    emit_text_to_reception("开始链接");
    QString output_path = project->_output_path;
    QStringList param = project->_linker_summary;
    param += linker_list;
    param << "-o" << output_path;
    emit_text_to_reception(param.join(' '));
    p.start("\"" + VGlobal::sdcc_path + "\"", param);
    if (p.waitForStarted() == false)
    {
        emit_text_to_reception("sdcc 启动失败");
        return;
    }
    p.waitForFinished();
    QString error = QString::fromLocal8Bit(p.readAllStandardError());
    emit_text_to_reception(error);
    emit_translate_build_error_info(QFileInfo(esln_path).path(), error);
    emit_text_to_reception("链接结束...");

	// 清空 lk map mem hex
	VFile::clear_folder_file(project->_output_folder, "(lk)(map)(mem)(hex)");
    // 判断ihx文件是否生成成功
    if(QFile(project->_output_path).exists())
    {
        p.start("\"" + VGlobal::packihx_path + "\"", QStringList() << project->_output_path);
        if (p.waitForStarted() == false)
        {
            emit_text_to_reception("packihx 启动失败");
            return;
        }
        p.waitForFinished();
        qDebug()<< QString::fromLocal8Bit(p.readAllStandardError());
        QString hex_text = p.readAllStandardOutput();
        VFunctions::save_file(project->_output_folder + "/" + project->_output_name + ".hex", hex_text);
        emit_text_to_reception("hex文件生成成功");
    }

	if(VGlobal::setting.delete_temp_files)
		delete_files(translate_files);
}

void VBackgroundSystem::slot_reload_testing()
{

    foreach(VFileData *data, _file_data_list)
    {
        uint time = QFileInfo(data->_path).lastModified().toTime_t();
        if(time > data->_last_modify_time)
        {
            QString text = VFunctions::read_file_text(data->_path);
            update_file_text(data, text);
            data->_last_modify_time = time;

			
        }
    }
}

void VBackgroundSystem::slot_set_file_last_time(QString path, uint time)
{
    auto data = file_data(path);
    if(data != nullptr)
    {
        data->_last_modify_time = time;
    }
}

void VBackgroundSystem::slot_reload_file(QString path)
{
    auto data = load_file_data(path);
	if (data == nullptr) return;
	update_file_text(data, VFunctions::read_file_text(data->_path));
	_update_queue.push_back(data->_path);
	_update_timer.start();
}

void VBackgroundSystem::slot_rename(QString old_path, QString new_path)
{
    auto data = file_data(old_path);
    if(data == nullptr) return;
    data->_path = new_path;
    data->_last_modify_time = QFileInfo(new_path).lastModified().toTime_t();

	update_all_file_include_data();
}

void VBackgroundSystem::slot_select_word(QString path, VWords *word)
{
    qDebug() << "select: " << word;

    if(word->_kind == VWords::KIND::KEYWORD)
    {
        foreach(VWords *obj, _template_list)
        {
            if(word->_name == obj->_name)
            {
                QList<VWords*> result;
                result.append(new VWords(obj));
                emit signals_calltip(result);
            }
        }
    }
    else if(word->_kind == VWords::FUNCTION
            || word->_kind == VWords::PROTOTYPE)
    {
        QString s_template = word->_name + "(";
        QStringList list = word->_signature.split(",");
        foreach(QString str, list)
        {
            if(str.isEmpty())
            {
                continue;
            }

            if(str.trimmed() == "...")
            {
                continue;
            }

            s_template += QString("/*-%1-*/, ").arg(str);
        }

        if(s_template.right(2) == ", ")
        {
            s_template.chop(2);
        }

        s_template += ")/*--*/";

        QList<VWords*> result;
        result.append(new VWords(word->_name, "", s_template, -1, VWords::KIND::TEMPLATE));
        emit signals_calltip(result);

    }

    if(word != nullptr)
    {
        delete word;
    }

}

void VBackgroundSystem::slot_open_project(QString path)
{
	if (get_project_data(path) == nullptr) {
		auto project  = new VProjectData(path);
		_project_list.append(project);
		update_project(project);
	}
}

void VBackgroundSystem::slot_close_project(QString path)
{
    auto project = get_project_data(path);
    if(project == nullptr) return;

    foreach(VFileData *file, _file_data_list)
    {
        if(file->_project == project)
            file->_project = nullptr;
    }

    delete project;
    _project_list.removeOne(project);


//    foreach(VProjectData *data, _project_list)
//    {
//        if(data->_path == path)
//        {
//            _project_list.removeOne(data);
//            delete data;
//            return;
//        }
//    }
}

void VBackgroundSystem::slot_reload_project(QString path)
{
    auto project = get_project_data(path);
    if(project == nullptr) return;
    project->reload();
	update_project(project);
}

void VBackgroundSystem::slot_delete_file(QString path)
{
	auto data = file_data(path);
	if(data == nullptr) return;
	_file_data_list.removeOne(data);
	update_all_file_include_data();
}

void VBackgroundSystem::slot_navigation(QString input, int type)
{
	QList<VNavigationWidget::NavigationData*> result;
	VFileData::VHeadFile file_parsing;
	QFileInfo info(input);
	file_parsing.name = info.fileName();
	file_parsing.path = info.path();

	if (type & VNavigationWidget::TYPE::FILE) {
		//QList<VDirData*> dir_data_list;
		//QList<QFileInfo> info_list;

		//foreach(VProjectData * project, _project_list) {
		//	info_list += VDirData(QFileInfo(project->_path).path()).search(file_parsing, "(h)(c)", 'p', false);
		//	dir_data_list += project->_include_path;
		//}
		//dir_data_list += _sdcc_source;

		//foreach(VDirData* data, dir_data_list){
		//	info_list += data->search(file_parsing, "(h)(c)", 'p', false);
		//}

		//foreach(const QFileInfo& mfi, info_list){
		//	result.append(new VNavigationWidget::NavigationData(mfi.filePath(), -1, mfi.fileName(), VWords::KIND::FILE));
		//}

		foreach(VFileData * data, _file_data_list) {
			QFileInfo info(data->_path);
			if (input.isEmpty() || VFunctions::matching_string(info.fileName(), input)) {
				result.append(new VNavigationWidget::NavigationData(info.filePath(), -1, info.fileName(), VWords::KIND::FILE));
			}
		}

	}
	if ((type & VNavigationWidget::SYMBOL) && input.isEmpty() == false) {
		foreach(VFileData * file, _file_data_list) {
			auto temp = file->_word_data->matching_childs(input, 0xFFFFFFFF, VWords::MATCH::NAME, -1, VWords::MODE::PART);
			foreach(VWords * word, temp) {
				result.append(new VNavigationWidget::NavigationData(file->_path, word->_line, word->_name, word->_kind));
			}
		}
	}

	emit signal_set_navigation(result);
}

void VBackgroundSystem::init_sdcc_source()
{
    _sdcc_source.clear();

    QString text = VFunctions::read_file_text(VGlobal::config_dir + "/include.txt");
    QStringList list = text.split("\r\n");
    foreach(QString dir, list)
    {
        if(dir.length() == 0)
        {
            continue;
        }

        _sdcc_source.append(new VDirData(dir.replace("..", VGlobal::current_dir)));
    }
}

QList<QFileInfo> VBackgroundSystem::search_sdcc_source_file(VFileData::VHeadFile file, char mode, bool folder)
{
    QList<QFileInfo> result;
    foreach(VDirData *data, _sdcc_source)
    {
        QList<QFileInfo> temp_list = data->search(file, "(h)", mode, folder);
        result += temp_list;
    }
    return result;
}

QList<QFileInfo> VBackgroundSystem::search_file(VProjectData *project, QString current_path, VFileData::VHeadFile file, char mode, bool folder)
{
    QList<QFileInfo> result;
    // 判断是 双引号 还是 尖括号
    // 尖括号 => 到标准路径下搜索
    // 双引号 => 先到本路径下搜索
    // 都没有找到 再到工程的目录下去搜索

    // 当前路径下搜索
    VDirData dir_data(current_path);
    result += dir_data.search(file, "(h)", mode, folder);

//    QDir dir;
//    dir.setCurrent(current_path);
//    dir.cd(file.path);
//    if(QFile(dir.absolutePath() + "/" + file.name).exists())
//    {
//        result.append(dir.absolutePath() + "/" + file.name);
//    }


    if(project != nullptr)
    {
        result += project->search(file, mode, folder);
    }

    result += search_sdcc_source_file(file, mode, folder);

    return result;
}

QList<VWords*> VBackgroundSystem::init_scope(QString path, int line, bool in_function)
{
    // 初始化搜索范围
    QList<VWords*> result;
    result.clear();

    // 加入关键字
    result += _keyword_list;

    VFileData* data = file_data(path);
    if(data == nullptr)
    {
        return QList<VWords*>();
    }

    // 寻找function
    if(in_function)
    {
        VWords *function = data->search_of_functon(line);
        if(function != nullptr)
        {
            result += function->_list;
        }
    }

    result += data->_word_data->_list;
    foreach(VFileData *data, data->_include_file_data_list)
    {
        result += data->_word_data->_list;
    }
    return result;
}

void VBackgroundSystem::init_include_dir()
{
    _include_dir_list.clear();

    QString text = VFunctions::read_file_text(VGlobal::config_dir + "/include.txt");
    // qDebug() << VGlobal::config_dir + "/include.txt";
    // qDebug() << text;
    QStringList list = text.split("\r\n");
    foreach(QString dir, list)
    {
        if(dir.length() == 0)
        {
            continue;
        }

        // _include_dir_list.append(dir.replace("..", VGlobal::current_dir));

        _include_folder_list.append(new VFolderData(dir.replace("..", VGlobal::current_dir)));
    }

    // qDebug() << _include_dir_list;
}

void VBackgroundSystem::init_keyword()
{
    foreach(QString key, VGlobal::keyword_cn_en.keys())
    {
        _keyword_list.append(new VWords(key, "", "", 0, VWords::KIND::KEYWORD));
    }

    foreach(QString key, VGlobal::keyword_en_cn.keys())
    {
        _keyword_list.append(new VWords(key, "", "", 0, VWords::KIND::KEYWORD));
    }

    // 加入一个函数模板
    QString s_template;
    s_template = "/*-返回类型-*/ /*-函数名称-*/(/*--*/)<br>{<br>    /*-代码内容-*/<br>}";
    _keyword_list.append(new VWords("函数模板", "", s_template, 0, VWords::KIND::TEMPLATE));
}

void VBackgroundSystem::init_template()
{
    _template_list.clear();
    QJsonObject object = VFunctions::get_file_jsonDocument(VGlobal::config_dir+"/template.json").object();
    foreach(QString key, object.keys())
    {
        _template_list.append(new VWords(key, "", object.value(key).toString(), -1, VWords::KIND::TEMPLATE));
    }
}

void VBackgroundSystem::init_path(QString path)
{
	QDir dir(QFileInfo(path).path());
	// qDebug() << QFileInfo(path).path();
//	if ( == false)
//	{
//		QMessageBox::warning(nullptr, "warning", path + "no cd up!");
//	}
	
    dir.cdUp();
	QString up_path = dir.path();

	_now_path = path;
    _now_dir = QFileInfo(path).path();

//    qDebug() << _module_folder_path;
}

QStringList VBackgroundSystem::get_file_all_include_paths(QString path)
{
    QStringList result;
    auto data = load_file_data(path);
    if(data == nullptr)
    {
        return result;
    }
    recursion_include(data->_project, path, result);
    return result;
}

void VBackgroundSystem::recursion_include(VProjectData *project, QString path, QStringList& result)
{
//    qDebug() << "recursion_include path:" << path;
    auto data = load_file_data(path);
    if(data == nullptr)
    {
        return;
    }

    QList<VFileData::VHeadFile> include_list = data->_include_list;
    foreach (VFileData::VHeadFile file_name, include_list)
    {

        QList<QFileInfo> temp_list = search_file(data->_project, QFileInfo(path).path(), file_name, 'a');
        if(temp_list.count() > 0 && result.contains(temp_list.at(0).absoluteFilePath()) == false)
        {
            result.append(temp_list.at(0).absoluteFilePath());
            recursion_include(project, temp_list.at(0).absoluteFilePath(), result);
        }
    }
}

QString VBackgroundSystem::read_file_text(QString path)
{
	QString result;
	VFileData *p = file_data(path);
	if (p != nullptr)
	{
		result = p->_text;
	}
	else
	{
		QFile file(path);
		if (file.open(QFile::ReadOnly) == false)
		{
            //QMessageBox::warning(nullptr, "warning", "can not open file" + path);
            return "";
		}

		QTextStream in(&file);
		in.setCodec("utf-8");
		result = in.readAll();
		file.close();
	}
    return result;
}

VProjectData *VBackgroundSystem::get_project_data(QString path)
{
    foreach (VProjectData* data, _project_list) {
        if(data->_path == path)
        {
            return data;
        }
    }
    return nullptr;
}

VFileData * VBackgroundSystem::file_data(QString path)
{
    foreach (VFileData* obj, _file_data_list)
	{
		if (obj->_path == path)
		{
			return obj;
		}
	}
    return nullptr;
}

VFileData *VBackgroundSystem::get_file_data(QString path)
{
    foreach (VFileData* obj, _file_data_list)
    {
        if (obj->_path == path)
        {
            return obj;
        }
    }
    return nullptr;
}

VFileData *VBackgroundSystem::set_file_text(QString path, QString text)
{
    qDebug() << "set file text";
    auto data = get_file_data(path);
    if(data == nullptr)
    {
        // 未载入这个文件
        // 判断文件是否存在
        if(QFile(path).exists() == false)
        {
            return nullptr;
        }

        // 载入这个文件
        data = new VFileData(path, text);
        _file_data_list.append(data);

        set_file_of_project(data);

        // 更新引入的文件数据
        update_file_include_data(data);
        update_all_file_include_data();
    }
    else
    {
        data->parsing_text(text);
        if(data->_include_changed)
        {
            // 更新引入的文件数据
//            emit signal_append_output_text("更新引入文件数据");
//            emit signal_append_output_text("=======================");
//            emit signal_append_output_text(data->_include_list.join('\n'));
            update_file_include_data(data);
            update_all_file_include_data();
            data->_include_changed = false;
        }
    }

//    qDebug() << data->_include_file_data_list.at(0)->_name;

    return data;
}

void VBackgroundSystem::update_file_text(VFileData *data, QString text)
{
    data->parsing_text(text);
    if(data->_include_changed)
    {
        update_file_include_data(data);
        update_all_file_include_data();
		update_project_external_depandence(data->_project);
        data->_include_changed = false;
    }
	_update_queue.push_back(data->_path);
	_update_timer.start();
}

VFileData *VBackgroundSystem::load_file_data(QString path)
{
    auto data = get_file_data(path);
    if(data != nullptr)
    {
        return data;
    }

    if(QFile(path).exists() == false)
    {
//        qDebug() << "load_file_error path:" << path;
        emit signal_append_output_text("load file error path:" + path);
        return nullptr;
    }

    QString text = VFunctions::read_file_text(path);

    // 载入这个文件
    data = new VFileData(path, text);
    set_file_of_project(data);
    _file_data_list.append(data);

    // 更新引入的文件数据
    update_file_include_data(data);
    return data;
}

void VBackgroundSystem::update_file_include_data(VFileData *data)
{
    data->_include_file_data_list.clear();
    QStringList list = get_file_all_include_paths(data->_path);
    foreach(QString path, list)
    {
        auto include_file_data = get_file_data(path);
        if(include_file_data != nullptr)
        {
            data->_include_file_data_list.append(include_file_data);
        }
    }
}

void VBackgroundSystem::update_all_file_include_data()
{
    foreach(VFileData *data, _file_data_list){
        update_file_include_data(data);
    }
}

void VBackgroundSystem::set_file_of_project(VFileData *data)
{
    qDebug() << "判断是否属于项目";
    data->_project = nullptr;
    foreach(VProjectData *project, _project_list)
    {
        if(project->is_child(data->_path))
        {
            data->_project = project;
            qDebug() << QString("file:%1 is %2 child.").arg(data->_path).arg(project->_path);
            break;
        }
    }
     qDebug() << "判断结束";
}

QString VBackgroundSystem::file_path(QString file_name, QStringList search_dir_list)
{

    foreach (QString dir, search_dir_list)
	{
		if (QFile(dir + "/" + file_name).exists())
		{
			return dir + "/" + file_name;
		}
	}

    foreach(VFolderData *ptr, _include_folder_list)
    {
        QString path = ptr->find_file(file_name);
        if(path.length() != 0)
        {
            return path;
        }
    }

//    qDebug() << "name:" << file_name << "no find";
	return "";
}

QList<VWords*> VBackgroundSystem::matching_keyword(QString input)
{
	QList<VWords*> result;
//    foreach (VWords* obj, _keyword_list)
//	{
//        if (obj->matching(input, VWords::KIND::KEYWORD, VWords::MATCH::NAME,
//                          -1, VWords::MODE::PART))
//		{
//			result.append(obj);
//		}
//	}
    return result;
}

void VBackgroundSystem::calltip_normal(QString input, int line_number, bool in_function)
{
//    qDebug() << "calltip_normal inpout:" << input;

//    QList<VWords*> list, temp_list;
//    temp_list = matching_keyword(input);

//    foreach(VFileData *p_file_data, _now_include_file_list)
//    {
////        VWords *ptr;
////        if(in_function)
////        {
////            ptr = p_file_data->search_of_functon(_now_path, input, line, VWords::MODE::PART);
////            if(ptr != nullptr)
////            {
////                temp_list.append(ptr);
////            }
////        }

//        temp_list += p_file_data->search_word(input, line_number, VFileData::MATCH::NAME, 0xFFFF, VWords::MODE::PART);
//    }

//    // 去掉重复的 function prototype
//    for(int i=0; i<temp_list.count(); i++)
//    {
//        if(temp_list.at(i)->_kind == VWords::FUNCTION
//                || temp_list.at(i)->_kind == VWords::PROTOTYPE)
//        {
//            for(int j=i+1; j<temp_list.count(); j++)
//            {
//                if((temp_list.at(j)->_kind == VWords::FUNCTION
//                        || temp_list.at(j)->_kind == VWords::PROTOTYPE)
//                        && temp_list.at(j)->_name == temp_list.at(i)->_name)
//                {
//                    temp_list.removeAt(j);
//                    j--;
//                }
//            }
//        }
//    }

//    // 将数据拷贝一份， 内存管理权限交给前端
//    foreach(VWords* obj, temp_list)
//    {
//        list.append(new VWords(obj));
//    }

//    emit signals_calltip(list);
}

void VBackgroundSystem::calltip_senior(QString input, int line_number, bool in_function)
{
//    QList<VInputBlock> list = get_input_list(input);
//    VWords * temp_word = nullptr;

//    int level;
//    int sum;
//    int symbol_level;
//    for(int i=0; i<list.count()-1; i++)
//    {
//        if(list.at(i).symbol == "->")
//        {
//            symbol_level = -1;
//        }
//        else
//        {
//            symbol_level = 0;
//        }

//        QString type_name = get_word_type(list.at(i).input, line_number, temp_word, level);
//        qDebug() << "type_name:" << type_name;
//        if(type_name.isEmpty())
//        {
//            qDebug() << "type_name.isEmpty()";
//            emit signals_calltip(QList<VWords*>());
//            return;
//        }

//        temp_word = get_struct(type_name, line_number, in_function);
//        if(temp_word == nullptr)
//        {
//           qDebug() << "temp_word == nullptr";
//            emit signals_calltip(QList<VWords*>());
//            return;
//        }

//        sum = level + symbol_level;

//        if(level + symbol_level != 0 && i != list.count()-2)
//        {
//            qDebug() << "level:" << level << "symbol_level:" <<symbol_level;
//            emit signals_calltip(QList<VWords*>());
//            return;
//        }
//    }

//    QString last = list.at(list.count()-1).input;
//    if(last.isEmpty() && level + symbol_level != 0)
//    {
//        if(sum == -1)
//        {
//            emit signal_change_symbol(".");
//        }
//        else if(sum == 1)
//        {
//            emit signal_change_symbol("->");
//        }
//    }

////    QList<VWords*> result;
////    foreach(VWords *obj, temp_word->_member_list)
////    {
//////        qDebug() << obj->_name;
////        if(last.isEmpty() || obj->matching_str(last))
////        {
////            result.append(new VWords(obj));
////        }
////    }
////    emit signals_calltip(result);

}

QList<VBackgroundSystem::VInputBlock> VBackgroundSystem::get_input_list(QString input)
{
    QList<VInputBlock> result;
    int pos = input.indexOf(QRegExp("\\.|->"));

    while(pos != -1)
    {

        QString str = input.left(pos);
        if(input.at(pos) == '.')
        {
            input.replace(0, pos+1, "");
            result.append(VInputBlock(str, "."));
        }
        else
        {
            input.replace(0, pos+2, "");
            result.append(VInputBlock(str, "->"));
        }

        pos = input.indexOf(QRegExp("\\.|->"));

    }
    result.append(VInputBlock(input, ""));

    return result;
}

QString VBackgroundSystem::get_word_type(QList<VWords*> &global_scope, QString name, int line, QList<VWords*> &scope, int &level)
{
    if(name.isEmpty())
    {
        return "";
    }

    QString result;
    QString type_name;
    // 去除两边的空格
    name = name.trimmed();

    // 判断是否是强制转换 (xxx)
    if(name.at(0) == '(' &&
            name.at(name.length()-1) == ')')
    {
        type_name = name;
    }
    // 判断是否是函数返回值 xxx()
    else if(name.right(2) == "()")
    {
        // 去掉括号
        name.chop(2);

        // 搜索scope
        QList<VWords*> list = search_scope_word(scope, name, VWords::KIND::FUNCTION | VWords::PROTOTYPE,
                          VWords::MATCH::NAME, line, VWords::MODE::ALL);

        if(list.count() != 0)
        {
            VWords * obj = list.at(0);
            type_name = obj->_type_name;
        }
    }
    else
    {
        // 搜索scope
        QList<VWords*> list = search_scope_word(scope, name, 0xFFFFFFFF,
                          VWords::MATCH::NAME, line, VWords::MODE::ALL);

        if(list.count() != 0)
        {
            VWords * obj = list.at(0);
            type_name = obj->_type_name;
        }
    }

    level = VFunctions::string_count(type_name, '*');
    QString str = VFunctions::string_reverse(type_name);
    QString type = VFunctions::string_regexp(str, "[a-zA-z_\u4e00-\u9fa5]+");
    result = VFunctions::string_reverse(type);

    // 判断result 是否是typedef
    // 搜索m_scope
    QList<VWords*> list = search_scope_word(global_scope, result, VWords::KIND::TYPEDEF,
                      VWords::MATCH::NAME, line, VWords::MODE::ALL);
    if(list.count() != 0)
    {
        VWords * obj = list.at(0);
        type_name = obj->_type_name;

        level += VFunctions::string_count(type_name, '*');
        QString str = VFunctions::string_reverse(type_name);
        QString type = VFunctions::string_regexp(str, "[a-zA-z_\u4e00-\u9fa5]+");
        result = VFunctions::string_reverse(type);
    }


    return result;

}

VWords *VBackgroundSystem::get_struct(QString name, int line_number, bool in_function)
{
//    QList<VWords*> list, temp_list;
//    foreach(VFileData *p_file_data, _now_include_file_list)
//    {
//        if (_now_path == p_file_data->_path)
//        {
//            temp_list = p_file_data->matching_string(name, in_function?line_number:-1, VWords::MODE::ALL);
//            if(temp_list.count() > 0)
//            {
//                foreach(VWords *obj, temp_list)
//                {
//                    if(obj->_name == name && obj->_kind == VWords::STRUCT)
//                    {
//                        return obj;
//                    }
//                }
//            }
//        }
//        else
//        {
//            list += p_file_data->matching_string(name, -1, VWords::MODE::ALL);
//        }
//    }

//    foreach(VWords *obj, list)
//    {
//        if(obj->_name == name && obj->_kind == VWords::STRUCT)
//        {
//            return obj;
//        }
//    }

    return nullptr;
}

QString VBackgroundSystem::text_preprocessing(QString text)
{
    // 正则替换
    QRegularExpression regexp;
    QRegularExpressionMatch match;

//    text = text.replace(" ", "");
    // 替换.  旁边的空格
    regexp.setPattern("\\s*\\.\\s*");
    match = regexp.match(text);
    while(match.hasMatch())
    {
        text = text.replace(match.capturedStart(), match.capturedLength(),
                            ".");
        match = regexp.match(text, match.capturedStart() + 1);
    }

    // 替换 -> 旁边的空格
    regexp.setPattern("\\s*->\\s*");
    match = regexp.match(text);
    while(match.hasMatch())
    {
        text = text.replace(match.capturedStart(), match.capturedLength(),
                            "->");
        match = regexp.match(text, match.capturedStart() + 2);
    }


    // 字符串方向
//    text = VFunctions::string_reverse(text);

    // 括号分组
   QString temp;
    int count = 0;
    int quotation_count = 0;
    int start = -1;
    int end;
    for(int i=0; i<text.length(); i++)
    {
        int unicode = text.at(i).unicode();
        switch (unicode) {
        case '(':
            count --;
            if(start == -1)
            {
                start = i;
                end = -1;
            }
            break;
        case ')':
            count ++;
            if(count == 0 && quotation_count%2 == 0)
            {
                // 找到括号组
                end = i;
                QString block = text.mid(start, end-start+1);

                // 强制转换
                regexp.setPattern("\\(\\s*(\\(.*?\\)).*?\\)");
                match = regexp.match(block);
                if(match.hasMatch())
                {
                    temp +=  match.captured(1);
                }
                else
                {
                    temp += "()";
                }

                // 重置start
                start = -1;
            }
            break;
        case '\'':
        case '\"':
            if(i==0 || (text.at(i-1) != '\\'))
            {
                // 非转义
                quotation_count++;
            }

            if(count == 0)
            {
                temp += text.at(i);
            }
            break;
        default:
            if(count >= 0)
            {
                temp += text.at(i);
            }
            break;
        }
    }

    // 没找到配对的括号
    if(start != -1 && end == -1)
    {
        temp += text.mid(start);
    }

    // 函数调用
    regexp.setPattern("([a-zA-z_\u4e00-\u9fa5]+)\\s*\\([^//(//)]*?\\)");
    match = regexp.match(temp);
    while(match.hasMatch())
    {
        temp = temp.replace(match.capturedStart(), match.capturedLength(),
                            match.captured(1) + "()");
        match = regexp.match(temp, match.capturedStart() +
                             match.capturedLength(1) + 2);
    }

//    // 函数调用
//    regexp.setPattern("\\s*\\).*?\\(\\s*([a-zA-z_\u4e00-\u9fa5]+)\\s*");
//    match = regexp.match(text);
//    while(match.hasMatch())
//    {
//        text = text.replace(match.capturedStart(), match.capturedLength(),
//                            ")(" + match.captured(1));
//        match = regexp.match(text, match.capturedStart() +
//                             match.capturedLength(1) + 2);
//    }

//    // 强制转换
//    regexp.setPattern("\\)[^\\(\\)]*?(\\).*?\\()\\(");
//    match = regexp.match(text);
//    while(match.hasMatch())
//    {
//        text = text.replace(match.capturedStart(), match.capturedLength(),
//                            match.captured(1));
//        match = regexp.match(text, match.capturedStart() + match.capturedLength());
//    }

    // 捕获input
//    regexp.setPattern("[a-zA-z_\u4e00-\u9fa5\\(\\)\\->\\.]+");
//    match = regexp.match(text);
//    if(match.hasMatch())
//    {
//        return VFunctions::string_reverse(match.captured());
//    }

    QString result;
    int branckets_count = 0;
    for(int i=temp.length()-1; i>=0; i--)
    {
        int unicode = temp.at(i).unicode();
        if( (unicode >= 'a' && unicode <= 'z') ||
                (unicode >= 'A' && unicode <= 'Z') ||
                (unicode >= '0' && unicode <= '9') ||
                (unicode >= 0x4E00 && unicode <= 0x9FA5) ||
                unicode == '_' ||
                unicode == '.' ||
                unicode == '-' ||
                unicode == '>' ||
                unicode == '(' ||
                unicode == ')' ||
                unicode == ' ' ||
                unicode == '*')
        {
            switch (unicode) {
            case '(':
                branckets_count--;
                if(branckets_count < 0)
                {
                    goto next;
                }
                else
                {
                    result = temp.at(i) + result;
                }
                break;
            case ')':
                branckets_count++;
                result = temp.at(i) + result;
                break;
            case '*':
            case ' ':
                if(branckets_count == 0)
                {
                    goto next;
                }
                result = temp.at(i) + result;
                break;
            case '-':
                if(i == temp.length()-1 || temp.at(i+1) != '>')
                {
                    goto next;
                }
                result = temp.at(i) + result;
                break;
            case '>':
                if(i == 0 || temp.at(i-1) != '-')
                {
                    goto next;
                }
                result = temp.at(i) + result;
                break;
            default:
                result = temp.at(i) + result;
                break;
            }

        }
        else
        {
            break;
        }
    }

    next:

    // 判断是否为 ()xxx
    regexp.setPattern("\\(\\)\\s*([a-zA-z_\u4e00-\u9fa5]+)");
    match = regexp.match(result);
    if(match.hasMatch())
    {
        result = match.captured(1);
    }
//    return VFunctions::string_reverse(result);
    return result;
}

QList<VWords *> VBackgroundSystem::search_scope_word(QList<VWords*> &scope, QString text, int kind, int match, int line, int mode)
{
    QList<VWords *> result;

    foreach(VWords *words,  scope)
    {
        if(words->matching(text, kind, match, -1, mode))
        {
            result.append(words);
        }
    }

    return result;
}

QList<VWords *> VBackgroundSystem::match_expression(QList<VWords*> &global_scope, QString expression, int mode, int *change_symbol)
{
    QList<VWords *> result;

    // 默认不需要更改符号
    if(change_symbol != nullptr)
    {
        (*change_symbol) = 0;
    }

    // 变量
    int level;
    int sum;
    int symbol_level;

    QList<VWords*> local_scope = global_scope;

    QList<VInputBlock> list = get_input_list(expression);
    for(int i=0; i<list.count()-1; i++)
    {
        if(list.at(i).symbol == "->")
        {
            symbol_level = -1;
        }
        else
        {
            symbol_level = 0;
        }

        QString type_name = get_word_type(global_scope, list.at(i).input, -1, local_scope, level);
        if(type_name.isEmpty())
        {
            return result;
        }

        local_scope = search_scope_word(global_scope, type_name, VWords::KIND::STRUCT | VWords::KIND::UNION,
                                        VWords::MATCH::NAME, -1, VWords::MODE::ALL);
        if(local_scope.count() == 0)
        {
            return result;
        }
        else
        {
            local_scope = local_scope.at(0)->_list;
        }

        sum = level + symbol_level;
        if(level + symbol_level != 0 && i != list.count() - 2)
        {
            return result;
        }
    }

    QString last = list.at(list.count()-1).input;
    if(last.isEmpty() && level + symbol_level != 0)
    {
        if(sum == -1)
        {
//            emit signal_change_symbol(".");
            if(change_symbol != nullptr)
            {
                (*change_symbol) = -1;
            }
        }
        else if(sum == 1)
        {
            if(change_symbol != nullptr)
            {
                (*change_symbol) = 1;
            }
//            emit signal_change_symbol("->");

        }
    }

    result = search_scope_word(local_scope, last, 0xFFFFFFFF, VWords::MATCH::NAME,
                                    -1, mode);
    return result;
}

void VBackgroundSystem::translate_file(QString path)
{

    auto file = load_file_data(path);
    if(file == nullptr)
    {
        return;
    }

    emit signal_append_output_text(file->_path);
    // 设置保存路径
    QFileInfo info(file->_path);
    QString folder_path = info.path();
    QString base_name = info.baseName();
    QString suffix = info.suffix();
    QString save_path = folder_path + "/" + VTranslate::encode_string63(base_name)
           + "." + suffix;
    emit signal_append_output_text(save_path);

    // 转为ascall
    VTranslate trans;
    trans.cn_en_map_append_keyword();
    trans.cn_en_map_append("主函数", "main");
    trans.set_comment_skip(true);
    trans.set_qutation_skip(true);
    QString text = trans.get_en_text(file->_text);

    // 正则替换 incldue
    QRegularExpression reg;
    QRegularExpressionMatch match;

    reg.setPattern("#include\\s+(\"|<)((.+?)\\.h)(\"|>)");
    match = reg.match(text);
    while(match.hasMatch())
    {
        QString base_name = match.captured(3);
        QString encode_name = VTranslate::encode_string63(base_name);
        text.replace(match.capturedStart(3), match.capturedLength(3), encode_name);
        match = reg.match(text, match.capturedStart(1));
    }

    VFunctions::save_file(save_path, text);
}

void VBackgroundSystem::translate_file(QString text, QString save_path)
{
    // 转为ascall
    VTranslate trans;
    trans.cn_en_map_append_keyword();
    trans.cn_en_map_append("主函数", "main");
    trans.set_comment_skip(true);
    trans.set_qutation_skip(true);
    text = trans.get_en_text(text);

    // 正则替换 incldue
    QRegularExpression reg;
    QRegularExpressionMatch match;

    reg.setPattern("#include\\s+(\"|<)((.+?)\\.h)(\"|>)");
    match = reg.match(text);
    while(match.hasMatch())
    {
        QString replace_text;
        if(match.captured(3).indexOf("/")!=-1)
        {
            QFileInfo info(match.captured(3).trimmed());
            QString path = info.path();
            QString base_name = info.fileName();
            QString encode_name = VTranslate::encode_string63(base_name);
            replace_text = path + "/" + encode_name;
        }
        else
        {
            QString base_name = match.captured(3);
            QString encode_name = VTranslate::encode_string63(base_name);
            replace_text = encode_name;
        }


        text.replace(match.capturedStart(3), match.capturedLength(3), replace_text);
        match = reg.match(text, match.capturedStart(1));
    }

    VFunctions::save_file_to_gbk(save_path, text);
}

void VBackgroundSystem::emit_text_to_reception(QString text)
{
    QRegularExpression reg;
    QRegularExpressionMatch match;

    reg.setPattern("____[a-zA-Z0-9_]+");
    match = reg.match(text);
    while(match.hasMatch())
    {
        QString dstring = VTranslate::decode_string63(match.captured());
        text = text.replace(match.capturedStart(), match.capturedLength(), dstring);
        match = reg.match(text, match.capturedStart() + dstring.length());
    }

    emit signal_append_output_text(text);
}

QList<QTreeWidgetItem*>  VBackgroundSystem::get_file_outline(VFileData* data, QTreeWidgetItem* parent)
{
	if (data == nullptr) return QList<QTreeWidgetItem*>();
	if (data->_project == nullptr) QList<QTreeWidgetItem*>();

	QList<VWords*> define_list;
	QList<VWords*> global_list;
	QList<VWords*> prototype_list;
	QList<VWords*> function_list;

	foreach(VWords * word, data->_word_data->_list) {
		switch (word->_kind)
		{
		case VWords::KIND::MARCO:
			define_list.append(word);
			break;
		case VWords::KIND::VARIABLE:
			global_list.append(word);
			break;
		case VWords::KIND::PROTOTYPE:
			prototype_list.append(word);
			break;
		case VWords::KIND::FUNCTION:
			function_list.append(word);
			break;
		default:
			break;
		}
	}

	QList<VWords*> list;
	list += define_list;
	list += global_list;
	list += prototype_list;
	list += function_list;

	QList<QTreeWidgetItem*> result;
	foreach(VWords * word, list) {
		if (word->_kind == VWords::KIND::PROTOTYPE) {
			auto item = new QTreeWidgetItem(parent);
			item->setText(0, word->_name + "(" + word->_signature + ")");
			item->setIcon(0, QIcon(VGlobal::icon_path.value("prototype")));
			item->setData(1, Qt::UserRole, QVariant::fromValue(VProjectTreeWidget::VItemData(
				VProjectTreeWidget::TreeWidgetItemType::ATTRIBUTE,
				data->_path, word->_line)));
			result.append(item);
		}
		else if (word->_kind == VWords::KIND::FUNCTION) {
			auto item = new QTreeWidgetItem(parent);
			item->setText(0, word->_name + "(" + word->_signature + ")");
			item->setIcon(0, QIcon(VGlobal::icon_path.value("function")));
			item->setData(1, Qt::UserRole, QVariant::fromValue(VProjectTreeWidget::VItemData(
				VProjectTreeWidget::TreeWidgetItemType::ATTRIBUTE,
				data->_path, word->_line)));
			result.append(item);
		}
		else if (word->_kind == VWords::KIND::MARCO) {
			auto item = new QTreeWidgetItem(parent);
			item->setText(0, word->_name);
			item->setIcon(0, QIcon(VGlobal::icon_path.value("define")));
			item->setData(1, Qt::UserRole, QVariant::fromValue(VProjectTreeWidget::VItemData(
				VProjectTreeWidget::TreeWidgetItemType::ATTRIBUTE,
				data->_path, word->_line)));
			result.append(item);
		}
		else if (word->_kind == VWords::KIND::VARIABLE) {
			auto item = new QTreeWidgetItem(parent);
			item->setText(0, word->_name);
			item->setIcon(0, QIcon(VGlobal::icon_path.value("global")));
			item->setData(1, Qt::UserRole, QVariant::fromValue(VProjectTreeWidget::VItemData(
				VProjectTreeWidget::TreeWidgetItemType::ATTRIBUTE,
				data->_path, word->_line)));
			result.append(item);
		}
	}
	return result;
}

void VBackgroundSystem::emit_translate_build_error_info(QString current_path, QString text)
{
    if(text.trimmed().isEmpty()) return;

    QList<VErrorWidget::VTableItem> result;
    QStringList error_list = text.split("\r\n");
    foreach (QString error_str, error_list)
    {
        if (error_str.trimmed().isEmpty()) continue;
        VOutputInformation parsing_error(error_str);

        int type;
        if(parsing_error._type == "warning")
        {type = VErrorWidget::VTableItemType::WARNING;}
        else if(parsing_error._type == "error")
        {type = VErrorWidget::VTableItemType::ERROR;}
        else if(parsing_error._type == "info")
        {type = VErrorWidget::VTableItemType::INFO;}

        result.append(VErrorWidget::VTableItem(type,
                                               parsing_error._error_number,
                                               parsing_error._text,
                                               current_path,
                                               parsing_error._path,
                                               parsing_error._line_number));
    }
    emit signal_show_build_information(result);
}

void VBackgroundSystem::update_file_outline(VFileData *data)
{
    if(data == nullptr) return;

	QList<VWords*> define_list;
	QList<VWords*> global_list;
	QList<VWords*> prototype_list;
	QList<VWords*> function_list;

	foreach(VWords * word, data->_word_data->_list) {
		switch (word->_kind)
		{
		case VWords::KIND::MARCO:
			define_list.append(word);
			break;
		case VWords::KIND::VARIABLE:
			global_list.append(word);
			break;
		case VWords::KIND::PROTOTYPE:
			prototype_list.append(word);
			break;
		case VWords::KIND::FUNCTION:
			function_list.append(word);
			break;
		default:
			break;
		}
	}

	QList<VWords*> list;
	list += define_list;
	list += global_list;
	list += prototype_list;
	list += function_list;

	QList<QTreeWidgetItem*> result;
	foreach(VWords* word, list) {
		if (word->_kind == VWords::KIND::PROTOTYPE) {
			auto item = new QTreeWidgetItem();
			item->setText(0, word->_name + "(" + word->_signature + ")");
			item->setIcon(0, QIcon(VGlobal::icon_path.value("prototype")));
			item->setData(1, Qt::UserRole, QVariant::fromValue(VProjectTreeWidget::VItemData(
				VProjectTreeWidget::TreeWidgetItemType::ATTRIBUTE,
				data->_path, word->_line)));
			result.append(item);
		}
		else if (word->_kind == VWords::KIND::FUNCTION) {
			auto item = new QTreeWidgetItem();
			item->setText(0, word->_name + "(" + word->_signature + ")");
			item->setIcon(0, QIcon(VGlobal::icon_path.value("function")));
			item->setData(1, Qt::UserRole, QVariant::fromValue(VProjectTreeWidget::VItemData(
				VProjectTreeWidget::TreeWidgetItemType::ATTRIBUTE,
				data->_path, word->_line)));
			result.append(item);
		}
		else if (word->_kind == VWords::KIND::MARCO) {
			auto item = new QTreeWidgetItem();
			item->setText(0, word->_name);
			item->setIcon(0, QIcon(VGlobal::icon_path.value("define")));
			item->setData(1, Qt::UserRole, QVariant::fromValue(VProjectTreeWidget::VItemData(
				VProjectTreeWidget::TreeWidgetItemType::ATTRIBUTE,
				data->_path, word->_line)));
			result.append(item);
		}
		else if (word->_kind == VWords::KIND::VARIABLE) {
			auto item = new QTreeWidgetItem();
			item->setText(0, word->_name);
			item->setIcon(0, QIcon(VGlobal::icon_path.value("global")));
			item->setData(1, Qt::UserRole, QVariant::fromValue(VProjectTreeWidget::VItemData(
				VProjectTreeWidget::TreeWidgetItemType::ATTRIBUTE,
				data->_path, word->_line)));
			result.append(item);
		}
	}

    emit signal_update_outline(data->_path, result);
}

void VBackgroundSystem::update_all_file_project()
{
    foreach(VFileData *data, _file_data_list){
        update_file_project(data);
    }
}

void VBackgroundSystem::update_file_project(VFileData *data)
{
    if(data == nullptr) return;
    data->_project = nullptr;
    foreach(VProjectData *project, _project_list){
        if(project->is_child(data->_path)){
            data->_project = project;
            return;
        }
    }
}

void VBackgroundSystem::set_file_outline(VFileData *data, QTreeWidgetItem* parent)
{
    if(data == nullptr) return;

    auto define_item = new QTreeWidgetItem(parent);
    define_item->setText(0, "宏定义");
    define_item->setIcon(0, QIcon(VGlobal::icon_path.value("define")));
    auto global_item = new QTreeWidgetItem(parent);
    global_item->setText(0, "全局变量");
    global_item->setIcon(0, QIcon(VGlobal::icon_path.value("global")));
    auto prototype_item = new QTreeWidgetItem(parent);
    prototype_item->setText(0, "函数声明");
    prototype_item->setIcon(0 ,QIcon(VGlobal::icon_path.value("prototype")));
    auto function_item = new QTreeWidgetItem(parent);
    function_item->setText(0, "函数定义");
    function_item->setIcon(0, QIcon(VGlobal::icon_path.value("function")));

    foreach(VWords *word,data->_word_data->_list)
    {
        if(word->_kind == VWords::KIND::PROTOTYPE){
            auto child = new QTreeWidgetItem(prototype_item);
            child->setText(0, word->_name + "(" + word->_signature + ")");
            child->setIcon(0 ,QIcon(VGlobal::icon_path.value("prototype")));
            child->setData(1, Qt::UserRole, QVariant::fromValue(VProjectTreeWidget::VItemData(
                                                                    VProjectTreeWidget::TreeWidgetItemType::ATTRIBUTE,
                                                                    data->_path, word->_line)));
        }else if(word->_kind == VWords::KIND::FUNCTION){
            auto child = new QTreeWidgetItem(function_item);
            child->setText(0, word->_name + "(" + word->_signature + ")");
            child->setIcon(0 ,QIcon(VGlobal::icon_path.value("function")));
            child->setData(1, Qt::UserRole, QVariant::fromValue(VProjectTreeWidget::VItemData(
                                                                    VProjectTreeWidget::TreeWidgetItemType::ATTRIBUTE,
                                                                    data->_path, word->_line)));
        }else if(word->_kind == VWords::KIND::MARCO){
            auto child = new QTreeWidgetItem(define_item);
            child->setText(0, word->_name);
            child->setIcon(0 ,QIcon(VGlobal::icon_path.value("define")));
            child->setData(1, Qt::UserRole, QVariant::fromValue(VProjectTreeWidget::VItemData(
                                                                    VProjectTreeWidget::TreeWidgetItemType::ATTRIBUTE,
                                                                    data->_path, word->_line)));
        }else if(word->_kind == VWords::KIND::VARIABLE){
            auto child = new QTreeWidgetItem(global_item);
            child->setText(0, word->_name);
            child->setIcon(0 ,QIcon(VGlobal::icon_path.value("global")));
            child->setData(1, Qt::UserRole, QVariant::fromValue(VProjectTreeWidget::VItemData(
                                                                    VProjectTreeWidget::TreeWidgetItemType::ATTRIBUTE,
                                                                    data->_path, word->_line)));
        }
    }
}

QStringList VBackgroundSystem::get_project_external_dependence(VProjectData *project)
{
    QStringList result;
    foreach(QString path, project->_project_file_path_list){
        auto data = load_file_data(path);
        if(data == nullptr) continue;
        foreach(VFileData* data_, data->_include_file_data_list)
        {
            if(result.contains(data_->_path) == false
                    && data_->_path.isEmpty() == false
                    && data_->_project != project)
                result.append(data_->_path);
        }
    }

    // 首字母排序
    std::sort(result.begin(),result.end(),[](const QString &a, const QString &b)
    {
        return QFileInfo(a).baseName().at(0) < QFileInfo(b).baseName().at(0);
    });

    return result;
}

void VBackgroundSystem::update_project_external_depandence(VProjectData* project)
{
	if (project == nullptr) return;
	//    emit_text_to_reception();
	QList<QTreeWidgetItem*> list;
	foreach(QString path, get_project_external_dependence(project))
	{
		auto data = load_file_data(path);
		if (data == nullptr) continue;
		auto item = new QTreeWidgetItem();
		item->setText(0, QFileInfo(path).fileName());
		item->setIcon(0, QIcon(VGlobal::icon_path.value("file_h")));
		item->setData(1, Qt::UserRole, QVariant::fromValue(VProjectTreeWidget::VItemData(
			VProjectTreeWidget::TreeWidgetItemType::FILE,
			data->_path, 0)));
		get_file_outline(data, item);
		list.append(item);
	}
	if (list.count())
		emit signal_update_project_external_dependence(project->_path, list);
}

void VBackgroundSystem::init_update_timer()
{
	_update_timer.setSingleShot(true);
	_update_timer.setInterval(3000);
	QObject::connect(&_update_timer, &QTimer::timeout, [this]() {
		if (this->_update_queue.count() > 0) {
			QString path = this->_update_queue.dequeue();
			auto data = load_file_data(path);
			update_file_outline(data);
			if (this->_update_queue.isEmpty() == false) {
				this->_update_timer.start();
			}
		}
	});
}

void VBackgroundSystem::update_project(VProjectData* project)
{
	if (project == nullptr) return;
	project->reload();
	foreach(QString path, project->_project_file_path_list)
	{
		auto file_data = load_file_data(path);
		update_file_outline(file_data);
	}
	update_all_file_project();
	update_all_file_include_data();
	update_project_external_depandence(project);
}

